package session.TX;

import javax.ejb.Stateless;
import entity.*;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javax.ejb.EJB;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

/**
 *
 * @author Randall Chia
 */
@Stateless
public class StakeholderBillingSB implements StakeholderBillingSBRemote {

    @PersistenceContext()
    EntityManager em;
    @EJB
    AdvertisementSBRemote adsRemote;
    private Date previousBillingDate;
    private Date currentBillingDate;

    //This method creates a new instance of StakeholderBill for each stakeholder. This method
    //is intended to be called once on the billing day of each month
    public void billStakeholders(Date previousDate, Date currentDate) {
        previousBillingDate = previousDate;
        currentBillingDate = currentDate;

        Query q1 = em.createQuery("SELECT c FROM Stakeholder c");

        for (Object o : q1.getResultList()) {
            Stakeholder stkhldr = (Stakeholder) o;
            if(stkhldr.isIsActivated()==false) continue; //Do not bill inactive stakeholders
            //TODO BILLING CODE

            //Make a new billing entity to hold the billing info
            StakeholderBill bill = new StakeholderBill();
            bill.create(stkhldr.getName(), currentBillingDate, 0.0, 0.0, 0.0, 0.0);


            //set the reinbursement (transaction revenue less commission)
            bill.setReInbursement(calculate_reinbursement(stkhldr.getName()));

            //set subscription fee
            bill.setBillSubscription(calculate_subscriptionFee(stkhldr.getName()));

            //set advertisement fee
            bill.setBillAdvertising(calculate_advertisingFee(stkhldr.getName()));

            //set the market intelligence fee (if a stakeholder is subscribed to market intelligence, he will be charged for it monthly)
            if (stkhldr.isPurchaseBI()) {
                //System.out.println(stkhldr.getName() + "Is subscribed to TTA");
                bill.setBillMarketIntelligence(calculate_marketIntelligenceFee(stkhldr.getName()));
            }

            //get Subtotal
            bill.computeSubtotal();
            
            
            //Print the bill details
            System.out.println("NEW BILL GENERATED FOR: " + stkhldr.getName() + " at time: " + currentDate);
            System.out.println("---------------------------------------------");
            System.out.println("Reimbursement: " + bill.getReInbursement());
            System.out.println("Subscription: " + bill.getBillSubscription());
            System.out.println("Advertising: " + bill.getBillAdvertising());
            System.out.println("Analytics Fee: " + bill.getBillMarketIntelligence());
            System.out.println("\nSUBTOTAL: " + bill.getSubTotal());
            System.out.println("---------------------------------------------\n");


            em.persist(bill);



            stkhldr.addBill(bill);
            em.flush();

            System.out.println("StakeholderBillingBean: Create bill SUCCESS for stakeholder: " + stkhldr.getName());


        }
    }//------------------------------------------------------------------------------------------

    private Double calculate_reinbursement(String stakeholderName) {
        Double returnValue = 0.0;
        Query q1 = em.createQuery("SELECT c FROM PurchasedItem c WHERE c.seller = :paramstakeholder AND c.time_stamp > :paramPreviousBillDate");
        q1.setParameter("paramstakeholder", stakeholderName);
        q1.setParameter("paramPreviousBillDate", previousBillingDate); //filter out all transactions before the previous billing date

        for (Object o : q1.getResultList()) {
            PurchasedItem item = (PurchasedItem) o;
            returnValue += item.getSubtotal();
        }
        //System.out.println(">>> StakeholderBillingBean: Billing " + stakeholderName + " Reinbursement: " + returnValue);
        return returnValue;
    }//------------------------------------------------------------------------------------------

    private Double calculate_subscriptionFee(String stakeholderName) {
        Stakeholder stkhldr = findStakeholderByName(stakeholderName);
        //System.out.println(">>> StakeholderBillingBean: Billing " + stakeholderName + " Subscription: " + stkhldr.getStakeholderTier().getFeeSubscription());
        return stkhldr.getStakeholderTier().getFeeSubscription();
    }//------------------------------------------------------------------------------------------

    private Double calculate_advertisingFee(String stakeholderName) {
        Double charges = 0.0;
        Integer clicks;
        Integer impression;
        boolean isclick;

        Stakeholder stkhldr = findStakeholderByName(stakeholderName);
        if (stkhldr != null) {
            Double clickPrice = stkhldr.getStakeholderTier().getCostPerClick();
            //System.out.println("clickprice" + clickPrice );
            List<Advertisement> adList = stkhldr.getAdvertisement();
            for (int i = 0; i < adList.size(); i++) {
                Advertisement ads = adList.get(i);
                isclick = ads.isIsClick();
                if(isclick==false)
                    clickPrice = 0.0;
                
                clicks = ads.getTotalClicks();
                impression = ads.getTotalImpression();
                
                charges += clicks * clickPrice + impression * ads.getBiddingPrice();
                ads.setTotalClicks(0);
                ads.setTotalImpression(0);
                //System.out.println(">>> StakeholderBillingBean: Billing " + stakeholderName + " Advertising: " + charges);
                em.flush();
            }
            

            
            return charges;
        }
        return 0.0;

    }//------------------------------------------------------------------------------------------

    private Double calculate_marketIntelligenceFee(String stakeholderName) {
        Stakeholder stkhldr = findStakeholderByName(stakeholderName);
        System.out.println(">>> StakeholderBillingBean: Billing " + stakeholderName + " MarketIntelligence: " + stkhldr.getStakeholderTier().getFeeMarketIntelligence());
        return stkhldr.getStakeholderTier().getFeeMarketIntelligence();
    }//------------------------------------------------------------------------------------------

    public Stakeholder findStakeholderByName(String stakeholderName) {
        Query q = em.createQuery("SELECT c FROM Stakeholder c WHERE c.name = :paramName");
        q.setParameter("paramName", stakeholderName);
        List resultList = q.getResultList();
        if (resultList.isEmpty()) {
            return null;
        }


        Stakeholder stakeholder = (Stakeholder) resultList.get(0);
        return stakeholder;
    }//------------------------------------------------------------------------------------------
    
    
    
    
    //Retrieve all bills for a particular month (since billing is done on a monthly basis)
    public List<StakeholderBill> retrieveBillsByMonth(int month, int year, boolean excludePaidBills){
        List<StakeholderBill> returnList = new ArrayList<StakeholderBill>();
        Query query = em.createQuery("SELECT c FROM StakeholderBill c");
        for(Object o : query.getResultList()){
            StakeholderBill bill = (StakeholderBill)o;
            Calendar cal = Calendar.getInstance();
            cal.setTime(bill.getBillDate());
            if(cal.get(Calendar.MONTH)== month && cal.get(Calendar.YEAR)== year ){
                if( (excludePaidBills && bill.isHasPaid()==false) || excludePaidBills==false){
                    returnList.add(bill);
                } 
            }
        }
        return returnList;
    }//------------------------------------------------------------------------------------------

    
    
    public void setBillAsPaid(Long billID){
        StakeholderBill bill;
        try{
            bill = em.find(StakeholderBill.class, billID);
        }catch (NullPointerException e){
            System.out.println(">>> StakeholderBillingSB: Attempt to find a bill that doesn't exist");
            return;
        }
        bill.setHasPaid(true);
        bill.setPaymentDate(new Date());
        em.flush();
        
    }//------------------------------------------------------------------------------------------
    
    
    
}
